package com.tplhk.drool.core.service.impl;


import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.resource.ResourceUtil;
import com.tplhk.drool.core.service.RuleEngineCoreService;
import lombok.extern.slf4j.Slf4j;
import org.kie.api.KieServices;
import org.kie.api.builder.KieBuilder;
import org.kie.api.builder.KieFileSystem;
import org.kie.api.builder.ReleaseId;
import org.kie.api.builder.model.KieModuleModel;
import org.kie.api.builder.model.KieSessionModel;
import org.kie.api.command.Command;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.StatelessKieSession;
import org.kie.internal.command.CommandFactory;

import java.io.File;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.*;

@Slf4j
public class RuleEngineCoreServiceImpl implements RuleEngineCoreService {

    public String PATHt = "droolRule";
    public String PATH = "src/main/resources/droolRule";
    public String GROUPID = "com.xiaoqiang";
    public String ARTIFACTID = "plusRules";
    public String VERSION = "1.0";


    private KieContainer kieContainer;
    private static KieServices kieServices;
    private static KieFileSystem kfs;
    private KieModuleModel kmm;

    private Map<String, StatelessKieSession> kieSessionMap = new HashMap<>();

    static {
        System.out.println("初始化 kieServices");
        kieServices = KieServices.Factory.get();
        kfs = kieServices.newKieFileSystem();
    }

    /**
     * 将规则文件载入 drools , 动态生成 Ksession
     * 1.1 创建 pom.xml
     * 1.2 创建 kmoudle.xml , 并编写 ksession 配置
     * 1.3 规则文件写入 kfs
     * 1.4 每一个规则创建一个 kession，写入 kieSessionMap
     *
     * @param ruleMap
     */
    @Override
    public void loadRule(Map<String, String> ruleMap) {
        System.out.println("(2) 动态生成 kiesession ...");
//        kieServices = KieServices.Factory.get();
//        kfs = kieServices.newKieFileSystem();
        // 创建 pom.xml
        ReleaseId rid = kieServices.newReleaseId(GROUPID, ARTIFACTID, VERSION);
        kfs.generateAndWritePomXML(rid);
        System.out.println("(2) 创建 pom.xml 成功");
        // 创建 kmoudle.xml
        kmm = kieServices.newKieModuleModel();
        System.out.println("(2) 创建 kmoudle.xml 成功");
        //所有规则写入 kmoudle.xml
        if (null != ruleMap && ruleMap.size() != 0) {
            for (Map.Entry<String, String> entry : ruleMap.entrySet()) {
                String path = PATH + "/" + entry.getKey() + "/" + entry.getKey() + ".drl";
                // 规则文件写入 kfs
                kfs.write(path, entry.getValue());
                // 编写 ksession 配置
                kmm.newKieBaseModel(entry.getKey() + "z")
                        //  package 路径相对于 resources
                        .addPackage(PATHt + "." + entry.getKey())
                        // 即 ksession.name
                        .newKieSessionModel(entry.getKey())
                        // 设置为无状态 ksession
                        .setType(KieSessionModel.KieSessionType.STATELESS);
            }
        }
        System.out.println("(2) 组建 kmoudle.xml 成功");
        kfs.writeKModuleXML(kmm.toXML());
        KieBuilder kieBuilder = kieServices.newKieBuilder(kfs);
        kieBuilder.buildAll();
        System.out.println("(2) 编写 kmoudle.xml 文件成功， 内容为：" + kmm.toXML());
        kieContainer = kieServices.newKieContainer(rid);
        kieContainer.updateToVersion(rid);

        this.updateKieSessionMap(ruleMap);
        System.out.println("(2) 动态生成 Ksession, 存入 kieSessionMap 成功， 长度为：" + kieSessionMap.size());
    }

    @Override
    public void invokRule(List<Command> commandList) {
        System.out.println("(3) 测试。。。");
        for (final Map.Entry<String, StatelessKieSession> entry : kieSessionMap.entrySet()) {
            new Thread(() -> {
                try {
//                    System.out.println("(3) 取出 session");
                    StatelessKieSession kieSession = entry.getValue();
                    kieSession.execute(CommandFactory.newBatchExecution(commandList));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }).start();
        }

        try {
            Thread.sleep(2 * 1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 更新规则
     *
     * @param ruleMap
     */
    @Override
    public void updateRule(Map<String, String> ruleMap) {
        ruleMap.forEach((k, v) -> {
            String path = PATH + "/" + k + "/" + k + ".drl";
            // 规则文件写入 kfs
            kfs.write(path, v);
            // 编写 ksession 配置
            kmm.newKieBaseModel(k + "z")
                    //  package 路径相对于 resources
                    .addPackage(PATHt + "." + k)
                    // 即 ksession.name
                    .newKieSessionModel(k)
                    // 设置为无状态 ksession
                    .setType(KieSessionModel.KieSessionType.STATELESS);
        });
        kfs.writeKModuleXML(kmm.toXML());
        KieBuilder kieBuilder = kieServices.newKieBuilder(kfs);
        kieBuilder.buildAll();
        System.out.println("更新 kmoudle.xml 文件成功， 内容为：" + kmm.toXML());
        ReleaseId rid = kieServices.newReleaseId(GROUPID, ARTIFACTID, VERSION);
        kieContainer.updateToVersion(rid);

        this.updateKieSessionMap(ruleMap);
        System.out.println("更新动态生成 Ksession, 存入 kieSessionMap 成功， 长度为：" + kieSessionMap.size());

    }

    private void updateKieSessionMap(Map<String, String> ruleMap) {
        if (null != ruleMap && ruleMap.size() != 0) {
            for (Map.Entry<String, String> entry : ruleMap.entrySet()) {
                StatelessKieSession kSession = kieContainer.newStatelessKieSession(entry.getKey());
                kieSessionMap.put(entry.getKey(), kSession);
            }
        }
    }

    /**
     * 加载数据库的规则
     *
     * @param ruleContentDB 数据库的记录
     * @return
     */
    public Map<String, String> loadRuleContentFromDB(Map<String, String> ruleContentDB) {
        System.out.println("(1) 加载规则文件");
        Map<String, String> map = new HashMap<>();
        map.put("rulename-3", rule3);
        map.put("rulename-4", rule4);
        return map;
    }

    /**
     * 传入目录，读取目录下的所有规则文件
     *
     * @param fileDir
     * @return
     */
    public Map<String, String> loadRuleContentFromFile(String fileDir) {
        System.out.println("(1) 加载规则文件");
        Map<String, String> map = new HashMap<>();
        URL resource = ResourceUtil.getResource(fileDir);
        File[] files = FileUtil.ls(resource.getFile());
        Arrays.stream(files).forEach(item -> {
            String fileContent = FileUtil.readString(item, StandardCharsets.UTF_8);
            String mainName = FileUtil.mainName(item);
//            log.error("mainName::::::::::" + mainName);
            map.put(mainName, fileContent);
        });
        return map;
    }

    private final String rule3 = "package droolrule;\n" +
            "import com.tplhk.drool.entity.RuleExcel ;\n" +
            "import com.tplhk.drool.entity.RuleResult;\n" +
            "import java.util.*;\n" +
            "import org.slf4j.Logger\n" +
            "import org.slf4j.LoggerFactory ;\n" +
            "\n" +
            "rule \"rulename-3\"\n" +
            "    salience 995\n" +
            "    when ruleExcel : RuleExcel(sex.equalsIgnoreCase(\"男\") && age<=20 && driver<=10 && websiteId.equalsIgnoreCase(\"10003\"))\n" +
            "       resultParam : List();\n" +
            "    then\n" +
            "        final Logger LOGGER = LoggerFactory.getLogger(\"rulename-333 规则引擎\") ;\n" +
            "        resultParam.add(\"转人工333\");\n" +
            "        LOGGER.info(\"resultParam = 转人工333\");\n" +
            "end";

    private final String rule4 = "package droolrule;\n" +
            "import com.tplhk.drool.entity.RuleExcel ;\n" +
            "import com.tplhk.drool.entity.RuleResult;\n" +
            "import java.util.*;\n" +
            "import org.slf4j.Logger\n" +
            "import org.slf4j.LoggerFactory ;\n" +
            "\n" +
            "rule \"rulename-4\"\n" +
            "    salience 996\n" +
            "    when ruleExcel : RuleExcel(sex.equalsIgnoreCase(\"男\") && age<=20 && driver<=10 && websiteId.equalsIgnoreCase(\"10003\"))\n" +
            "       resultParam : List();\n" +
            "    then\n" +
            "        final Logger LOGGER = LoggerFactory.getLogger(\"rulename-4 规则引擎\") ;\n" +
            "        resultParam.add(\"转人工4\");\n" +
            "        LOGGER.info(\"resultParam = 转人工4\");\n" +
            "end";

}
